﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using MyDLL;
using MyWinFormDLL;

namespace Rtz2Xlsx
{
    public partial class FormMain : Form
    {
        public static string filePath_Full_Settings = Application.StartupPath.Replace(@"bin\Debug", "") + @"Settings\Settings.xml";
        public static string xpath_ToPlan = "";
        public static string planSelected = "";
        public static string[] plans = null;
        public static List<string[]> Attribute_Parent_Plus_NodeNames_Children_StrList = null;
        public static XML_Commons xML_Commons = new XML_Commons(FormMain.filePath_Full_Settings);
        public static string xpath_Plan = "/" + XmlSettings.settings + "/" + XmlSettings.plan;

        public string cbBoxPlan
        {
            get {return comboBoxSettingsPlans.Text; }
            set {comboBoxSettingsPlans.Text=value; }
        }

        public static ComboBox comboBoxSettingsPlans_Static;

        //从FormMain更新comboBox
        public static void UpdateComboBoxSettingsPlans()
        {
            comboBoxSettingsPlans_Static.Items.Clear();
            for (int i = 0; i < FormMain.plans.Length; i++)
            {
                comboBoxSettingsPlans_Static.Items.Add(FormMain.plans[i]);
            }
            comboBoxSettingsPlans_Static.Text = comboBoxSettingsPlans_Static.Items[0].ToString();
            FormMain.planSelected = comboBoxSettingsPlans_Static.Text;
        }

        //从其他Form更新comboBox
        public static void UpdateComboBoxSettingsPlans_FromOtherForms()
        {
            comboBoxSettingsPlans_Static.Items.Clear();
            for (int i = 0; i < FormMain.plans.Length; i++)
            {
                comboBoxSettingsPlans_Static.Items.Add(FormMain.plans[i]);
            }
            comboBoxSettingsPlans_Static.Text = FormMain.planSelected;
        }
        public FormMain()
        {
            InitializeComponent();
        }

        private void buttonSelectFiles_Click(object sender, EventArgs e)
        {
            List<string> filePathList = new List<string>();
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                for (int i = 0; i < openFileDialog1.FileNames.Length; i++)
                {
                    filePathList.Add(openFileDialog1.FileNames[i]);
                }
            }
            string[] strArr = new string[5];
            for (int i = 0; i < filePathList.Count; i++)
            {
                strArr = GetFileInfo(filePathList[i]);
                if (!IsTargetFileFormat(strArr[3],"rtz") && !IsTargetFileFormat(strArr[3], "txt")) //如果不是rtz或txt，则弹出提示
                {
                    MessageBox.Show("不能加载非rtz或txt文件！");
                    continue;
                }
                MyDataGridViewAddRow(strArr);
            }
        }

        /// <summary>
        /// 获取文件信息
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns>输出一个5个元素的字符串数组</returns>
        private string[] GetFileInfo(string filePath)
        {
            string[] strArr = new string[5];
            /*  ================
             *  Index   内容
             *  ----------------
             *  0       文件名
             *  1       修改时间
             *  2       大小
             *  3       文件类型
             *  4       路径
             *  ================
             */

            //获取文件名
            FileInfo fileInfo = new FileInfo(filePath);
            strArr[0] = fileInfo.Name.ToString();
            strArr[1] = fileInfo.LastWriteTime.ToString();
            strArr[2] = Math.Ceiling(fileInfo.Length / 1024.0) + " KB";
            strArr[3] = fileInfo.Extension.ToString().Replace(".", string.Empty);
            strArr[4] = filePath;

            return strArr;
        }

        /// <summary>
        /// 判断文件类型是否为目标格式。
        /// </summary>
        /// <param name="fileType"></param>
        /// <param name="fileType_Target"></param>
        /// <returns></returns>
        private bool IsTargetFileFormat(string fileType, string fileType_Target)
        {
            bool retVal = true;
            if (fileType != fileType_Target && fileType != fileType_Target.ToUpper())
            {
                retVal = false;
            }
            return retVal;
        }

        /// <summary>
        /// 在DataGridView中添加行
        /// </summary>
        /// <param name="strArr">长度为5的字符串数组</param>
        private void MyDataGridViewAddRow(string[] strArr)
        {
            DataGridViewRow dr = new DataGridViewRow();
            DataGridViewCell cell1 = new DataGridViewTextBoxCell();//文件名
            DataGridViewCell cell2 = new DataGridViewTextBoxCell();//修改时间
            DataGridViewCell cell3 = new DataGridViewTextBoxCell();//大小
            DataGridViewCell cell4 = new DataGridViewTextBoxCell();//文件类型
            DataGridViewCell cell5 = new DataGridViewTextBoxCell();//路径

            cell1.Value = strArr[0];
            cell2.Value = strArr[1];
            cell3.Value = strArr[2];
            cell4.Value = strArr[3];
            cell5.Value = strArr[4];

            dr.Cells.Add(cell1);
            dr.Cells.Add(cell2);
            dr.Cells.Add(cell3);
            dr.Cells.Add(cell4);
            dr.Cells.Add(cell5);

            dgvFileSelection.Rows.Add(dr);
        }

        #region 拖拽文件到DataGridView
        private void dgvFileSelection_DragDrop(object sender, DragEventArgs e)
        {
            Array fileArr = (System.Array)e.Data.GetData(DataFormats.FileDrop);
            string filePath = "";
            string[] strArr = new string[5];
            foreach (object item in fileArr)
            {
                filePath = item.ToString();
                strArr = GetFileInfo(filePath);
                if (!IsTargetFileFormat(strArr[3],"rtz") && !IsTargetFileFormat(strArr[3], "txt")) //如果不是rtz或txt，则弹出提示
                {
                    MessageBox.Show("不能加载非rtz或txt文件！");
                    continue;
                }
                MyDataGridViewAddRow(strArr);
            }
        }

        private void dgvFileSelection_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Link;
            else
                e.Effect = DragDropEffects.None;
        }
        #endregion

        private void tsmiDelete_Click(object sender, EventArgs e)
        {
            List<int> selectedRowsList = new List<int>();
            foreach (DataGridViewCell item in dgvFileSelection.SelectedCells)
            {
                selectedRowsList.Add(item.RowIndex);
            }
            selectedRowsList = selectedRowsList.Distinct().ToList();
            for (int i = 0; i < selectedRowsList.Count; i++)
            {
                dgvFileSelection.Rows.RemoveAt(selectedRowsList[i]);
            }
        }

        //给datagridview添加序号

        private void dgvFileSelection_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        {
            DataGridView dgv = sender as DataGridView;
            System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(e.RowBounds.Location.X,
                                                e.RowBounds.Location.Y,
                                                dgv.RowHeadersWidth - 4,
                                                e.RowBounds.Height);


            TextRenderer.DrawText(e.Graphics, (e.RowIndex + 1).ToString(),
                                    dgv.RowHeadersDefaultCellStyle.Font,
                                    rectangle,
                                    dgv.RowHeadersDefaultCellStyle.ForeColor,
                                    TextFormatFlags.VerticalCenter | TextFormatFlags.Right);
        }

        //开始转换
        private void buttonStartConversion_Click(object sender, EventArgs e)
        {            
            if (dgvFileSelection.Rows.Count != 0)   //如果DataGridView不为空
            {
                if (Directory.Exists(textBoxPath.Text))//存在路径则执行
                {
                    List<string> filePathList_RTZ = new List<string>();
                    List<string> filePathList_XLSX = new List<string>();
                    string path = textBoxPath.Text + @"\";
                    string[] headers = FormMain.Attribute_Parent_Plus_NodeNames_Children_StrList[1][0].Split(',');
                    string[] separateArr = FormMain.Attribute_Parent_Plus_NodeNames_Children_StrList[1][1].Split(new string[]{ "||"},StringSplitOptions.RemoveEmptyEntries);
                    string[] regexArr = null;
                    int[] splitArr = null;
                    if(separateArr.Length == 2) //如果既有正则表达式，又有字节数
                    {
                        splitArr = BasicDataProcess_Common.String_to_IntArr(separateArr[1]); //分隔数组
                        regexArr = separateArr[0].Split(',');
                    }
                    else //如果只有字节数，没有正则表达式
                    {
                        splitArr = BasicDataProcess_Common.String_to_IntArr(separateArr[0]); //分隔数组
                    }
                    string encodingStr = FormMain.Attribute_Parent_Plus_NodeNames_Children_StrList[1][2];

                    //将dgv中的文件路径添加到filePathList_RTZ中
                    for (int i = 0; i < dgvFileSelection.Rows.Count; i++)
                    {
                        filePathList_RTZ.Add(dgvFileSelection.Rows[i].Cells[4].Value.ToString());//获取RTZ文件路径，存入List中
                    }

                    //添加XLSX保存路径
                    for (int i = 0; i < dgvFileSelection.Rows.Count; i++)
                    {
                        filePathList_XLSX.Add(path + StringUtility.GetFullFileName_ExcludingSuffix(dgvFileSelection.Rows[i].Cells[0].Value.ToString()));//添加XLSX保存路径
                    }

                    ExtractMethod extractMethod = ExtractMethod.Columns;
                    //if(radioButton_Columns.Checked)
                    //    extractMethod = ExtractMethod.Columns;
                    if (radioButton_LinesOnly.Checked)
                        extractMethod = ExtractMethod.LinesOnly;
                    if (radioButton_ColumnsFull.Checked)
                    {
                        extractMethod = ExtractMethod.ColumnsFull;
                    }

                    ExportMethod exportMethod = ExportMethod.Xlsx_Slow;
                    //if (radioButton_XlsxSlow.Checked)
                    //    exportMethod = ExportMethod.Xlsx_Slow;
                    if (radioButton_XlsxFast.Checked)
                        exportMethod = ExportMethod.Xlsx_Fast;
                    if (radioButton_xlsxBitFast.Checked)
                        exportMethod = ExportMethod.Xlsx_BitFast;

                    for (int i = 0; i < filePathList_RTZ.Count; i++)
                    {
                        ConvertToXlsx(filePathList_RTZ[i], filePathList_XLSX[i], headers, regexArr, splitArr, extractMethod, exportMethod, encodingStr);
                    }
                    dgvFileSelection.Rows.Clear();
                }
                else
                {
                    MessageBox.Show("路径不存在！");
                }
            }
            else
            {
                MessageBox.Show("未选择任何文件！");
            }
        }

        private enum ExtractMethod
        {
            Columns,
            ColumnsFull,
            LinesOnly
        }

        private enum ExportMethod
        {
            Xlsx_Slow,
            Xlsx_Fast,
            Xlsx_BitFast
        }

        class State
        {
            private int pageNum;
            /// <summary>
            /// 页序号，0-based
            /// </summary>
            public int PageNum
            {
                get { return pageNum; }
                set 
                { 
                    pageNum = value;
                    for (int i = 0; i < this.regexHdrs.Length; i++)
                    {
                        this.regexHdrs[i] = false;
                    }
                }
            }

            /// <summary>
            /// 正则表达式deHeaders的判断数组
            /// </summary>
            public bool[] regexHdrs { get; set; }

            private HorD h_d;
            /// <summary>
            /// Headers or Data Contents
            /// </summary>
            public HorD H_D
            {
                get 
                {
                    if (this.regexHdrs != null && this.regexHdrs.Any(x => x == false))
                        this.h_d = HorD.Headers;
                    else
                        this.h_d = HorD.Data;

                    return h_d; 
                }
                set { h_d = value; }
            }

            public State(int regexHdrsC)
            {
                if(regexHdrsC > 0)
                {
                    this.regexHdrs = new bool[regexHdrsC];
                    this.PageNum = 0;
                }
            }
        }

        /// <summary>
        /// Headers or Data Contents
        /// </summary>
        enum HorD
        {
            /// <summary>
            /// 表头行
            /// </summary>
            Headers,
            /// <summary>
            /// 数据行
            /// </summary>
            Data
        }

        /// <summary>
        /// 解析rtz并转换成xlsx
        /// </summary>
        /// <param name="fullFilePath_RTZ">RTZ文件路径</param>
        /// <param name="fullFilePath">XLSX文件保存路径</param>
        /// <param name="columnsHeadersArr">各列标题</param>
        /// <param name="regexArr">正则表达式数组</param>
        /// <param name="splitArr">按byte分割数组</param>
        /// <param name="encodingStr_RTZ">RTZ文件编码</param>
        /// <param name="exportMethod">转换方式</param>
        /// <param name="extractMethod">取数方式</param>
        private void ConvertToXlsx(string fullFilePath_RTZ, string fullFilePath, string[] columnsHeadersArr,string[] regexArr, int[] splitArr, ExtractMethod extractMethod, ExportMethod exportMethod, string encodingStr_RTZ = "GBK")
        {
            String_N_Byte string_N_Byte = new String_N_Byte();
            StreamReader sr = new StreamReader(fullFilePath_RTZ, Encoding.Default);

            int splitSum = 0;
            for (int i = 0; i < splitArr.Length; i++)
            {
                splitSum += splitArr[i];
            }

            System.Data.DataTable dt_Temp = null;

            string[] resStrSplitArr = null;
            string str = sr.ReadLine();
            
            switch (extractMethod)
            {
                case ExtractMethod.Columns: //分列精简
                    dt_Temp = DataTable_Common_Static.DataTable_HeadersSetting<string>(columnsHeadersArr);
                    int regexArrLen = 0;
                    if (regexArr != null)
                        regexArrLen = regexArr.Length;
                    int regexArr_splitArr_Len = regexArrLen + splitArr.Length;
                    string[] regexContentArr = new string[regexArrLen]; //存储表头信息的临时数组
                    State state = new State(regexArrLen);
                    while (!sr.EndOfStream)
                    {
                        //if (string_N_Byte.GetByteLength(str, encodingStr_RTZ) == splitSum) //数据行
                        if (state.H_D == HorD.Data) //数据行
                        {
                            if(string_N_Byte.GetByteLength(str, encodingStr_RTZ) == splitSum)
                            {
                                //读取数据
                                resStrSplitArr = BasicDataProcess_Common.StringArrTrim(string_N_Byte.StringSplit_perByte(str, splitArr, encodingStr_RTZ));
                                int[] colIndexes = BasicDataProcess_Common.IntArrayGenerator(regexArrLen, 1, regexArr_splitArr_Len);
                                DataTable_Common_Static.input1DArr_to_DataTable_ByRow_Specify_Columns<string>(dt_Temp, resStrSplitArr, colIndexes);

                                //填写表头信息
                                if (regexArrLen != 0)
                                {
                                    for (int j = 0; j < regexArrLen; j++)
                                    {
                                        dt_Temp.Rows[dt_Temp.Rows.Count - 1][j] = regexContentArr[j];
                                    }
                                }
                            }
                            else if(string_N_Byte.GetByteLength(str, encodingStr_RTZ) <= 45)//专门适用于科目汇总帐
                            {
                                dt_Temp.Rows[dt_Temp.Rows.Count - 1][4] += str.Trim();
                            }
                        }
                        else if(state.H_D == HorD.Headers) //表头行
                        {
                            if(regexArrLen != 0)
                            {
                                for (int j = 0; j < regexArrLen; j++)
                                {
                                    string tempStr = Regex_Common.MatchCollection_Results(regexArr[j], str)[0].Trim();
                                    if (tempStr != "无匹配结果")
                                    {
                                        regexContentArr[j] = tempStr;
                                        state.regexHdrs[j] = true;
                                    }
                                }
                            }
                        }
                        str = sr.ReadLine();
                        if (str.Contains('\f'))
                            state.PageNum++;
                    }
                    break;

                case ExtractMethod.LinesOnly: //仅分行
                    dt_Temp = new DataTable();
                    dt_Temp.Columns.Add("账表",typeof(String));
                    int i = 0;
                    while (str != null)
                    {
                        str = sr.ReadLine();
                        dt_Temp.Rows.Add(dt_Temp.NewRow());
                        dt_Temp.Rows[i][0] = str;
                        i++;
                    }
                    break;

                case ExtractMethod.ColumnsFull: //分列全
                    dt_Temp = DataTable_Common_Static.DataTable_HeadersSetting<string>(columnsHeadersArr);
                    while (str != null)
                    {
                        if (string_N_Byte.GetByteLength(str, encodingStr_RTZ) == splitSum)
                        {
                            resStrSplitArr = BasicDataProcess_Common.StringArrTrim(string_N_Byte.StringSplit_perByte(str, splitArr, encodingStr_RTZ));
                            DataTable_Common_Static.input1DArr_to_DataTable<string>(dt_Temp, resStrSplitArr);
                        }
                        else
                        {
                            resStrSplitArr = new string[1];
                            resStrSplitArr[0] = str;
                            DataTable_Common_Static.input1DArr_to_DataTable<string>(dt_Temp, resStrSplitArr);
                        }
                        str = sr.ReadLine();
                    }
                    break;
                default:
                    break;
            }

            //写入excel
            switch (exportMethod)
            {
                case ExportMethod.Xlsx_Slow:
                    //DataTable_Common_Static.DataTable_to_Excel_UsingClosedXML(dt_Temp, fullFilePath + ".xlsx");
                    MyExcelUtility.ExcelOleDbUtility.DataTableToXlsx(dt_Temp, fullFilePath + ".xlsx");
                    break;
                case ExportMethod.Xlsx_Fast:
                    DataTable_Common.DataTableToExcel(dt_Temp, fullFilePath + ".xls");
                    break;
                case ExportMethod.Xlsx_BitFast:
                    DataTable_Common_Static.DataTable_to_Excel_UsingClosedXML(dt_Temp, fullFilePath + ".xlsx");
                    break;
                default:
                    break;
            }
        }

        //选择导出路径
        private void buttonSelectPath_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                textBoxPath.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void buttonSettings_Click(object sender, EventArgs e)
        {
            FormSettings formSettings = new FormSettings();
            formSettings.Show();
        }
        public static bool IsFormOpen(Form frm)
        {
            bool retVal = false;
            string frmName = frm.Name;
            FormCollection fc = Application.OpenForms;
            foreach (Form openFrm in fc)
            {
                if (openFrm.Name == frmName)
                {
                    retVal = true;
                }
            }
            return retVal;
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            comboBoxSettingsPlans_Static = comboBoxSettingsPlans;
            UpdateXmlInfo_ByIndex();
            UpdateComboBoxSettingsPlans();
        }

        /// <summary>
        /// 加载FormMain的时候更新xml信息（只获取第一个方案的信息）。
        /// </summary>
        public static void UpdateXmlInfo_ByIndex()
        {
            string[] NodeNamesPlan = new string[1] { XmlSettings.plan };
            FormMain.xpath_ToPlan = "/" + XmlSettings.settings + "/" + XmlSettings.plan + "[1]";
            FormMain.Attribute_Parent_Plus_NodeNames_Children_StrList = xML_Commons.Xml_ParentAttributes_Plus_ChildrenNodesInnerText_ToStringArrListByXpath_ToParentRetrieveChildren(FormMain.xpath_ToPlan, XmlSettings.Attributes_Parent, XmlSettings.NodeNames_Children);
            string[] arrTemp_Attribute =new string[1] { XmlSettings.planAttribute_1 };
            List<string[]> listTemp = FormMain.xML_Commons.AllSelectedNodesSelectedAttributes(FormMain.xpath_Plan, arrTemp_Attribute);
            FormMain.plans = new string[listTemp.Count];
            for (int i = 0; i < listTemp.Count; i++)
            {
                plans[i] = listTemp[i][0];
            }            
        }

        /// <summary>
        /// 程序运行时，按需依name属性更新xml信息。
        /// </summary>
        /// <param name="planName">方案名称</param>
        public static void UpdateXmlInfo_ByAttribute_1(string planName)
        {
            string[] NodeNamesPlan = new string[1] { XmlSettings.plan };
            FormMain.xpath_ToPlan = "/" + XmlSettings.settings + "/" + XmlSettings.plan + "[@" + XmlSettings.planAttribute_1 + "='" + planName + "']";
            FormMain.Attribute_Parent_Plus_NodeNames_Children_StrList = xML_Commons.Xml_ParentAttributes_Plus_ChildrenNodesInnerText_ToStringArrListByXpath_ToParentRetrieveChildren(FormMain.xpath_ToPlan, XmlSettings.Attributes_Parent, XmlSettings.NodeNames_Children);
            string[] arrTemp_Attribute = new string[1] { XmlSettings.planAttribute_1 };
            List<string[]> listTemp = FormMain.xML_Commons.AllSelectedNodesSelectedAttributes(FormMain.xpath_Plan, arrTemp_Attribute);
            FormMain.plans = new string[listTemp.Count];
            for (int i = 0; i < listTemp.Count; i++)
            {
                plans[i] = listTemp[i][0];
            }
        }

        private void comboBoxSettingsPlans_SelectedValueChanged(object sender, EventArgs e)
        {
            UpdateXmlInfo_ByAttribute_1(comboBoxSettingsPlans.SelectedItem.ToString());
            FormMain.planSelected = comboBoxSettingsPlans.Text;
        }
    }
}